import asyncio
import time
import traceback
import json
import uuid
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime

import aiohttp
from urllib.parse import urlencode
from bot.insurance_planner_gpt.interface.base_handler import BaseHandler
from bot.insurance_planner_gpt.qw_server.common import wework_constants
from bot.insurance_planner_gpt.qw_server.access_token_manager import token_manager
from bot.insurance_planner_gpt.qw_server.qw_process.qw_process_contact import QWContactCallBackProcess
from bot.insurance_planner_gpt.qw_server.qw_process.qw_process_msg import QWMsgCallBackProcess
from bot.insurance_planner_gpt.qw_server.qw_process.qw_process_robot import QWRobotCallBackProcess, get_addwechat_robot
from bot.insurance_planner_gpt.qw_server.utils import common_util
from bot.insurance_planner_gpt.qw_server.utils import wechat
from bot.insurance_planner_gpt.qw_server.utils.signature_util import Signature, EncodeData
from bot.insurance_planner_gpt.wechat_sop_server import send_wechat_sop_message, send_browsing_history
from bot.insurance_planner_gpt.wechat_sop_server import send_wechat_sop_image, get_customer_id_url, send_msg_robot
from common.common_exception import CommonException
from common.log import logger
import requests
from db.mysql.entity_service import EntitiesDao
from db.redis.redis_service import RedisMemory

redis_memory = RedisMemory()
loops = asyncio.get_event_loop()
redis_memory.delete("active_sessions:qw")
entities_dao = EntitiesDao()


class WeWorkProcessHandler(BaseHandler):
    max_thread_num = 10
    executor = ThreadPoolExecutor(max_workers=max_thread_num)

    async def post(self, path):
        """请求分发"""
        match path:
            case 'add_contact_by_phone':
                phone = self.get_argument('phone', '')
                company_id = self.get_argument('company_id', '')
                session_id = self.get_argument('session_id', '')
                customer_id = self.get_argument('customer_id', '')
                user_name = self.get_argument('user_name', '')
                case_id = self.get_argument('case_id', '')
                if not company_id:
                    output = "请输入空间id"
                else:
                    company_info = common_util.get_info_by_company_id(common_util.wework_config_list, company_id)
                    verify_msg = company_info.get("VERIFY_MSG", "")
                    output = await self.add_contact_by_phone(phone, verify_msg, company_id, customer_id, session_id,
                                                             user_name, case_id)
            case 'handle_call_back':
                data = self.get_argument('data', '')
                company_id = self.get_argument('company_id', '')
                output = await self.handle_callback(data, company_id)
            case 'send_sop_msg':
                body = self.request.body
                body_json = json.loads(body)
                add_wechat_day = body_json.get('add_wechat_day', '')
                msg = body_json.get('msg', '')
                msg_type = body_json.get('msg_type', '')
                output = await send_wechat_sop_message(add_wechat_day, msg, msg_type)
            case 'call_back':
                output = ""
                try:
                    encode_data = EncodeData.from_json(self.request.body)
                    # 验证签名 解密
                    if encode_data.signature == Signature.get_signature(encode_data):
                        data = Signature.decode_content(encode_data.encoding_content, encode_data.aes_key)
                        company_info = common_util.get_info_by_app_key(common_util.wework_config_list,
                                                                       encode_data.app_key)
                        company_id = company_info.get("COMPANY_ID", None)
                        output = await self.handle_callback(data, company_id)
                except CommonException:
                    logger.error(traceback.format_exc())
                    output = "服务处理异常"
                    self.set_status(500)
                    await self.finish()
                except Exception:
                    logger.error(traceback.format_exc())
                    output = "回调验证签名，解密异常"
            case 'get_all_robot':
                company_id = self.get_argument('company_id', '')
                if not company_id:
                    output = '请输入空间id'
                else:
                    token = await token_manager.get_access_token_by_company_id(company_id)
                    output = self.get_all_robot(token)
            case 'send_sop_image':
                file_name = self.request.files.get("img")[0].get("filename")
                file_type = self.request.files.get("img")[0].get("content_type")
                file_bytes = self.request.files.get("img")[0].get("body")
                output = await send_wechat_sop_image(file_name, file_type, file_bytes)
            case 'get_customer_service_account':
                company_id = self.get_argument('company_id', '')
                if not company_id:
                    output = '请输入空间id'
                else:
                    token = await token_manager.get_access_token_by_company_id(company_id)
                    output = await self.get_customer_service_account(token, company_id)
            case _:
                logger.warning(f"/wework/{path} 没有该路径!")
                output = '没有找到对应的服务'

        self.write(json.dumps(output, ensure_ascii=False))

    async def get(self, path):
        match path:
            case 'agree_add_wechat':
                session_id = self.get_argument('session_id', '')
                phone_number = self.get_argument('phone_number', '')
                user_name = self.get_argument('user_name', '')
                company_id = self.get_argument('company_id', '')
                customer_id = self.get_argument('customer_id', '')
                case_id = self.get_argument('case_id', '')

                params = {"session_id": session_id,
                          "phone_number": phone_number,
                          "user_name": user_name,
                          "company_id": company_id,
                          "customer_id": customer_id,
                          "case_id": case_id}

                await self.agree_add_wechat(params)
            case 'retry_add_wechat':
                customer_id = self.get_argument('customer_id', '')
                logger.info(f"服务异常：未获取到加微串码，发起重试，客户id:{customer_id}")
                await self.retry_add_wechat(customer_id)
            case 'get_customer_id_url':
                customer_id = self.get_argument('customer_id', '')
                url = self.get_argument('url', '')
                return self.write(await get_customer_id_url(customer_id, url))
            case 'send_msg_qw_robot':
                contact_id = self.get_argument('contact_id', '')
                robot_id = self.get_argument('robot_id', '')
                msg = self.get_argument('msg', '')
                send_type = self.get_argument('send_type', '')
                return self.write(await send_msg_robot(contact_id, robot_id, msg, send_type))
            case 'index/product/detail':
                request_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                args = self.request.arguments
                customer_id = self.get_argument('customer_id', '')
                company = self.get_argument('company', '')
                url = 'https://www.huize.com/apps/cps/index/product/detail'
                params = {}
                if args:
                    params = {k: v[0].decode() for k, v in args.items() if k not in ['customer_id', 'company']}
                    params_url = urlencode(params)
                    if 'huize' == company:
                        url = 'https://www.huize.com/apps/cps/index/product/detail'
                    url = url + "?" + params_url
                loops.run_in_executor(None, send_browsing_history, customer_id, company, url, params,
                                      request_time)
                self.redirect(url)
                return
        self.write("ok")

    async def handle_callback(self, data, company_id=None):
        """ 处理回调 """
        try:
            message = json.loads(data)
            logger.info("接收到回调消息==" + str(message))
            event_type = message.get("event_type")
            err_code = message.get("err_code")
            err_msg = message.get("err_msg")
            req_id = message.get("uniq_sn", "")
            robot_id = message.get("robot_id", "")
            data = message.get("data", "")
            if 0 == err_code and event_type:
                # 处理机器人小助相关的回调
                if wework_constants.WEWORK_EVENT_TYPE_GET_ROBOT_LIST == event_type or \
                        wework_constants.WEWORK_EVENT_TYPE_ROBOT_LOG_OUT == event_type or \
                        wework_constants.WEWORK_EVENT_TYPE_ROBOT_LOGIN_SUCCESS == event_type:
                    await QWRobotCallBackProcess(company_id, event_type, robot_id, req_id,
                                                 message).process_all_event_type()
                # 处理消息相关的回调
                elif wework_constants.WEWORK_EVENT_TYPE_RECEIVE_CONTACT_MSG == event_type or \
                        wework_constants.WEWORK_EVENT_TYPE_DOWNLOAD_CHAT_FILE == event_type or \
                        wework_constants.WEWORK_EVENT_TYPE_TRANCE_VOICE == event_type or \
                        wework_constants.WEWORK_EVENT_TYPE_SEND_CONTACT_MSG == event_type:
                    # if company_id != '2252':
                    await QWMsgCallBackProcess(company_id, event_type, robot_id, req_id,
                                               message).process_all_event_type()
                    # elif company_id in [2252,'2252']:
                    #     # 消息入库

                # 处理联系人相关的回调
                elif wework_constants.WEWORK_EVENT_TYPE_BECOME_CONTACT == event_type \
                        or wework_constants.WEWORK_EVENT_TYPE_GET_CONTACT == event_type \
                        or wework_constants.WEWORK_EVENT_TYPE_CONTACT_APPLY_REQ == event_type \
                        or wework_constants.WEWORK_EVENT_TYPE_ADD_CONTACT_BY_PHONE == event_type:
                    await QWContactCallBackProcess(company_id, event_type, robot_id, req_id,
                                                   message).process_all_event_type()
            else:
                logger.error(f"请求标识 uniq_sn:{req_id},回调异常：{err_msg}")
                phone = data.get('phone', '')
                if wework_constants.WEWORK_EVENT_TYPE_ADD_CONTACT_BY_PHONE == event_type:
                    if company_id in [2252, '2252']:
                        robotName = common_util.get_robot_name(redis_memory=redis_memory, company_id=company_id,
                                                               robot_id=robot_id)

                        content_dict = {
                            "加好友通知": "❌申请发送失败\n客服企微：【{}】\n微信手机号：【{}】\n失败原因：【{}】".format(
                                robotName,
                                phone, err_msg)}
                        wechat.send_wechat(msg=content_dict, webhook=wework_constants.webhook_url)
                        wechat.send_wechat(msg=content_dict, webhook=wework_constants.webhook_url_guoan)
                    # if company_id in [2242, '2242']:
                    #     robotName = common_util.get_robot_name(redis_memory=redis_memory, company_id=company_id,
                    #                                            robot_id=robot_id)
                    #     content_dict = {
                    #         "加好友通知": "❌申请发送失败\n客服企微：【{}】\n微信手机号：【{}】\n失败原因：【{}】".format(robotName,
                    #                                                                     phone,
                    #                                                                     err_msg)}
                    #     wechat.send_wechat(msg=content_dict, webhook=wework_constants.webhook_huize_url)
                    #
                    # if company_id in [2243, '2243']:
                    #     robotName = common_util.get_robot_name(redis_memory=redis_memory, company_id=company_id,
                    #                                            robot_id=robot_id)
                    #     content_dict = {
                    #         "加好友通知": "❌申请发送失败\n客服企微：【{}】\n微信手机号：【{}】\n失败原因：【{}】".format(robotName,
                    #                                                                     phone,
                    #                                                                     err_msg)}
                    #     wechat.send_wechat(msg=content_dict, webhook=wework_constants.webhook_huize_url)
                loops.run_in_executor(None, entities_dao.update_ql_add_wechat_record, phone, -1, err_msg, '',
                                      '')
        except CommonException:
            logger.error(traceback.format_exc())
        except Exception:
            logger.error(traceback.format_exc())
        return "回调处理成功"

    async def add_contact_by_phone(self, phone, verify_msg="", company_id=None, customer_id="", session_id="",
                                   user_name="", case_id=None):
        """通过手机号添加好友"""
        response_json = {}
        robot_id = ""
        try:
            # 获取token
            token = await token_manager.get_access_token_by_company_id(company_id)

            logger.info(
                'phone-{},company_id-{},customer_id-{},session_id-{},user_name-{},case_id-{}'
                .format(phone, company_id, customer_id, session_id, user_name, case_id))
            if phone:
                # 获取一个机器人
                # todo
                mark_id = session_id
                if customer_id:
                    mark_id = session_id + "," + customer_id

                robot_id = get_addwechat_robot(company_id, user_name)
                if not verify_msg:
                    verify_msg = wework_constants.WEWORK_ADD_CONTACT_VERIFY_MSG
                payload = {
                    "robot_id": robot_id,
                    "phone": phone,
                    "verify_msg": verify_msg,
                    "mark_id": mark_id
                }
                logger.info('add_by_phone:{}'.format(payload))
                headers = {'Content-Type': 'application/json', 'Token': token}
                async with aiohttp.ClientSession() as session:
                    async with session.post(wework_constants.WEWORK_INTERFACE_ADD_CONTACT_BY_PHONE, json=payload,
                                            headers=headers) as response:
                        data = await response.json()
                        if response.status == 200 and data.get("errcode") == 0:
                            response_json['message'] = "请求发送成功"
                            loops.run_in_executor(None, entities_dao.insert_ql_add_wechat_record, session_id,
                                                  customer_id,
                                                  robot_id, datetime.now(), '', phone, '', company_id, case_id)
                        else:
                            response_json['message'] = data.get("err_msg")
        except Exception:
            logger.error(traceback.format_exc())
            response_json['message'] = "请求异常"
        logger.info(
            f"添加的手机串码为:{phone},会话id是：{session_id},使用的机器人id是:{robot_id} ,请求结果：{response_json['message']}")
        return response_json

    async def agree_add_wechat(self, params):
        """获取电话的加微串码发起加微"""
        session_id = params.get('session_id', '')
        phone_number = params.get('phone_number', '')
        user_name = params.get('user_name', '')
        company_id = params.get('company_id', '')
        customer_id = params.get('customer_id', '')
        case_id = params.get('case_id', '')

        try:
            # todo 区分信贷顾问   和  小助 ...
            session_company_id = ''
            if session_id:
                session_company_id, session_case_id = common_util.get_info_from_session_id(session_id)

            if (company_id and company_id in [2252, '2252']) or (
                    session_id and session_company_id and session_company_id in [2252, '2252']):
                if not company_id:
                    company_id, case_id = common_util.get_info_from_session_id(session_id)

                company_info = common_util.get_info_by_company_id(common_util.wework_config_list, company_id)
                verify_msg = company_info.get("VERIFY_MSG", "")

                await self.add_contact_by_phone(phone_number, verify_msg, company_id, customer_id,
                                                session_id, user_name, case_id)
            else:
                # 解析session_id
                company_id, case_id = common_util.get_info_from_session_id(session_id)
                # 调用零犀平台接口获取加微串码
                url = wework_constants.GET_ADD_WECHAT_CODE.format(session_id)
                company_info = common_util.get_info_by_company_id(common_util.wework_config_list, company_id)
                verify_msg = company_info.get("VERIFY_MSG", "")
                async with aiohttp.ClientSession() as session:
                    async with session.get(url) as response:
                        response_case = await response.json()
                        if response_case:
                            wechat_code = response_case.get("wechatCode", "")
                            customerId = response_case.get("customerId", "")
                            logger.info(f"从电销平台查询的会话为:{session_id},查询结果是:{str(response_case)}")
                            if phone_number:
                                await self.add_contact_by_phone(phone_number, verify_msg, company_id, customerId,
                                                                session_id)
                            elif wechat_code and not phone_number:
                                await self.add_contact_by_phone(wechat_code, verify_msg, company_id, customerId,
                                                                session_id)
                            elif not phone_number and not wechat_code:
                                logger.info(f"服务异常:会话:{session_id},未查询到加微串码")
                                redis_memory.hset(wework_constants.QW_PLANNER_REDIS_KEY_PREFIX + "find_code_error",
                                                  customerId, session_id)
        except Exception:
            logger.error(f"会话:{session_id},从电销平台查询案件串码异常:{traceback.format_exc()}")

    async def retry_add_wechat(self, customer_id):
        """ 没获取到加微串码后重试 """
        try:
            if customer_id:
                session_id = redis_memory.hget(wework_constants.QW_PLANNER_REDIS_KEY_PREFIX + "find_code_error",
                                               customer_id)
                if session_id:
                    # 停顿50s 等待RPA重启后重新抓数
                    company_id, case_id = common_util.get_info_from_session_id(session_id)
                    url = wework_constants.GET_ADD_WECHAT_CODE.format(session_id)
                    company_info = common_util.get_info_by_company_id(common_util.wework_config_list, company_id)
                    verify_msg = company_info.get("VERIFY_MSG", "")
                    time.sleep(50)
                    async with aiohttp.ClientSession() as session:
                        async with session.get(url) as response:
                            response_case = await response.json()
                            if response_case:
                                wechat_code = response_case.get("wechatCode", "")
                                customerId = response_case.get("customerId", "")
                                logger.info(f"从电销平台查询的会话为:{session_id},查询结果是:{str(response_case)}")
                                if wechat_code:
                                    await self.add_contact_by_phone(wechat_code, verify_msg, company_id, customerId,
                                                                    session_id)
                                    redis_memory.hdel(wework_constants.QW_PLANNER_REDIS_KEY_PREFIX + "find_code_error",
                                                      customerId)
                                else:
                                    logger.info(f"会话:{session_id},重试异常，未查询到加微串码")
        except Exception:
            logger.error(f"客户id:{customer_id},重试异常:{traceback.format_exc()}")

    async def get_customer_service_account(self, token, company_id):
        """调用获取客服账号信息"""
        response_json = {}
        try:
            payload = {
                "limit": 100,
            }
            headers = {'Content-Type': 'application/json', 'Token': token}
            async with aiohttp.ClientSession() as session:
                async with session.post(wework_constants.WEWORK_INTERFACE_GET_CUSTOMER_SERVICE_LIST, json=payload,
                                        headers=headers) as response:
                    data = await response.json()
                    if response.status == 200 and data.get("errcode") == 0:
                        account_data = data.get("data")
                        account_list = account_data.get("list", [])
                        if company_id in [2252, '2252']:
                            await self.push_customers_to_redis(company_id, account_list)
                        else:
                            for account in account_list:
                                login_id = account.get("login_id", "")
                                robot_list = account.get("robot_list", [])
                                for robot in robot_list:
                                    robot_id = robot.get("robot_id", "")
                                    login_status = robot.get("login_status", 1)
                                    if login_status == 1:
                                        redis_memory.sadd(
                                            wework_constants.QW_PLANNER_REDIS_KEY_PREFIX + "robot_customer_service:" + robot_id,
                                            login_id)
                    else:
                        response_json['message'] = data.get("err_msg")
        except Exception:
            response_json['message'] = "请求异常"
        return response_json

    # 分组将客服--在线企微 存到redis
    async def push_customers_to_redis(self, company_id, account_list):
        try:
            for account in account_list:
                login_id = account.get("login_id", "")
                robot_list = account.get("robot_list", [])
                back_robot_list = []
                for robot in robot_list:
                    robot_id = robot.get("robot_id", "")
                    login_status = robot.get("login_status", 1)
                    if login_status == 1:
                        back_robot_list.append(robot_id)

                        # 总量存
                        redis_memory.sadd(
                            wework_constants.QW_PLANNER_REDIS_KEY_PREFIX + "acquire_robot:" + str(company_id), robot_id)

                # 分客服存
                if back_robot_list and len(back_robot_list) > 0:
                    redis_memory.delete(wework_constants.QW_PLANNER_REDIS_KEY_PREFIX + "username_add_wechat:" + str(
                        company_id) + ":" + str(login_id))
                    redis_memory.lpushall(wework_constants.QW_PLANNER_REDIS_KEY_PREFIX + "username_add_wechat:" + str(
                        company_id) + ":" + str(login_id), list(back_robot_list))
        except Exception as ee:
            logger.error(traceback.format_exc())

    async def get_contact_info(self, token, robot_id, contact_id, ):
        """调用获取联系人信息"""
        response_json = {}
        try:
            payload = {
                "robot_id": robot_id,
                "contact_id": contact_id,
                "uniq_sn": str(uuid.uuid4()).replace("-", "")
            }
            headers = {'Content-Type': 'application/json', 'Token': token}
            async with aiohttp.ClientSession() as session:
                async with session.post(wework_constants.WEWORK_INTERFACE_GET_CONTACT_INFO, json=payload,
                                        headers=headers) as response:
                    data = await response.json()
                    if response.status == 200 and data.get("errcode") == 0:
                        response_json['message'] = "请求发送成功"
                    else:
                        response_json['message'] = data.get("err_msg")
        except Exception:
            response_json['message'] = "请求异常"
        return response_json

    async def get_all_robot(self, token):
        """获取机器人列表"""
        response_json = {}
        try:
            payload = {
                "uniq_sn": str(uuid.uuid4()).replace("-", "")
            }
            headers = {'Content-Type': 'application/json', 'Token': token}
            async with aiohttp.ClientSession() as session:
                async with session.post(wework_constants.WEWORK_INTERFACE_GET_ROBOT_LIST, json=payload,
                                        headers=headers) as response:
                    data = await response.json()
                    if response.status == 200 and data.get("errcode") == 0:
                        response_json['message'] = "请求发送成功"
                    else:
                        response_json['message'] = data.get("err_msg")
        except Exception:
            response_json['message'] = "请求异常"
        return response_json
